package com.dysoft.flesh.gl;

import com.dysoft.flesh.RenderContext;
import com.dysoft.flesh.RenderTarget;
import com.dysoft.flesh.ui.UiCanvas;
import com.dysoft.flesh.ui.UiRenderer;

import javax.media.opengl.GL;
import javax.media.opengl.glu.GLU;
import java.awt.*;
import java.awt.geom.PathIterator;

/**
 * @author Sean Micklethwaite
 *         Oct 26, 2010 10:12:34 PM
 *
 * Starts UI rendering in OpenGL orthographic projection, with
 * depth buffer disabled.
 */
public class GLUiCanvas extends UiCanvas {
	static GLU glu = new GLU();

	public GLUiCanvas(Root root, RenderTarget target) {
		super(root, target);
	}

	@Override
	public boolean call(RenderContext ctx) {
		GL gl = ((GLRenderer.GLRenderContext)ctx).getGL();
		int w = ctx.getTarget().getWidth(), h = ctx.getTarget().getHeight();

		gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPushMatrix();
        gl.glLoadIdentity();

		glu.gluOrtho2D(0, w, 0, h);
        gl.glScalef(1, -1, 1);
        gl.glTranslatef(0, -h, 0);

        gl.glMatrixMode(GL.GL_MODELVIEW);

		boolean depth = gl.glIsEnabled(GL.GL_DEPTH_TEST);
		boolean blend = gl.glIsEnabled(GL.GL_DEPTH_TEST);
		boolean scissor = gl.glIsEnabled(GL.GL_SCISSOR_TEST);
		if(depth) gl.glDisable(GL.GL_DEPTH_TEST);
		if(!blend) gl.glEnable(GL.GL_BLEND);
		if(!scissor) gl.glEnable(GL.GL_SCISSOR_TEST);

		boolean keep = super.call(ctx);

		if(!scissor) gl.glDisable(GL.GL_SCISSOR_TEST);
		if(!blend) gl.glDisable(GL.GL_BLEND);
		if(depth) gl.glEnable(GL.GL_DEPTH_TEST);
		
		gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glPopMatrix();
        gl.glMatrixMode(GL.GL_MODELVIEW);

		return keep;
	}

	protected Context createContext(RenderContext ctx, Shape shape, Point offset) {
		return new Context(ctx, shape, offset);
	}
	
	public static class Fill implements UiRenderer {
		public void render(Context ctx) {
			Shape shape = ctx.getShape();
			Rectangle bounds = shape.getBounds();
			double x = bounds.getCenterX(), y = bounds.getCenterY();
			PathIterator path = shape.getPathIterator(null, 0.5);

			GL gl = ((GLRenderer.GLRenderContext)ctx.getRenderContext()).getGL();

			double [] v = new double[6];

			gl.glPushMatrix();
			gl.glTranslatef(ctx.getOffset().x, ctx.getOffset().y, 0);

			gl.glBegin(GL.GL_TRIANGLE_FAN);

			gl.glVertex2d(x, y); // Start from centre

			double startx = 0, starty = 0;
			while(!path.isDone()) {
				switch(path.currentSegment(v)) {
					case PathIterator.SEG_LINETO:
						gl.glVertex2dv(v, 0);
						break;
					case PathIterator.SEG_MOVETO:
						startx = v[0]; starty = v[1];
						gl.glVertex2dv(v, 0);
						break;
					case PathIterator.SEG_CLOSE:
						gl.glVertex2d(startx, starty);
						break;
					case PathIterator.SEG_QUADTO:
						gl.glVertex2dv(v, 0);
						gl.glVertex2dv(v, 2);
						break;
					case PathIterator.SEG_CUBICTO:
						gl.glVertex2dv(v, 0);
						gl.glVertex2dv(v, 2);
						gl.glVertex2dv(v, 4);
						break;
				}
				path.next();
			}

			gl.glEnd();
			gl.glPopMatrix();
		}
	}

	class Context extends UiCanvas.Context {
		Context(RenderContext ctx, Shape region, Point offset) {
			super(ctx, region, offset);
		}

		@Override
		protected void setDrawRegion(Rectangle region) {
			((GLRenderer.GLRenderContext)getRenderContext()).getGL().glScissor(
					(int)region.getMinX(),
					getTarget().getHeight() - (int)(region.getMinY() + region.getHeight()),
					(int)region.getWidth(), (int)region.getHeight()
			);
		}
	}
}
